home *** CD-ROM | disk | FTP | other *** search
/ HyperLib 1997 Winter - Disc 1 / HYPERLIB-1997-Winter-CD1.ISO.7z / HYPERLIB-1997-Winter-CD1.ISO / オンラインウェア / PRG / ICProgKit 1.3.sit / ICProgKit1.3 / Goodies / ICGenericOverride / ICGenericOverride.p next >
Text File  |  1995-04-23  |  15KB  |  432 lines

  1. unit ICGenericOverride;
  2.  
  3. (* Internet Config Generic Overide Component *)
  4.  
  5. (* Routine names have an ICGO prefix for Internet Config Generic Override. *)
  6.  
  7. (* This component is the framework for an Internet Config override *)
  8. (* component. I've used it to replace the original IC ReadOnly and *)
  9. (* IC RandomSignature components bodies with one common body. *)
  10. (* The different between the two components is now contained isolated *)
  11. (* in a separate file, ICSpecificOverride. *)
  12.  
  13. (* The component overrides the Internet Config Extension and *)
  14. (* passes all calls through to the specific override to determine *)
  15. (* whether it should be overridden. *)
  16.  
  17. (* This code has followed a fairly long path--Jager was the one who *)
  18. (* originally started the work on the Random Signature component. *)
  19. (* I based my code on his code and tried to get it work, in the *)
  20. (* process finding and using some sample code from a develop article. *)
  21. (* Eric translated the generic  parts of Random Signature to C to *)
  22. (* implement a component of his own (fixing bugs and rewriting along *)
  23. (* the way), and then modified to duplicate the behavior of *)
  24. (* IC ReadOnly. Since then I have ported the changes back to Pascal *)
  25. (* to form the basis of this generic override component, which I've *)
  26. (* used for the IC 1.1 override components. *)
  27.  
  28. (* Consider it a collaborative work, as Eric *)
  29. (* says "a bit of a Frankenstein's monster". *)
  30.  
  31. (* This release fixes a nasty bug in the Pascal example components, one which *)
  32. (* prevents them from loading if their manufacturer code comes after *)
  33. (* that of a previously registered component. If you use any component *)
  34. (* based on this code, the old versions of IC ReadOnly and Random *)
  35. (* Signature will probably stop working. *)
  36.  
  37. (* If you're implementing a component of your own, I strongly suggest *)
  38. (* you contact either Eric or myself first. In any event, read *)
  39. (* the section on the component manager in Inside Macintosh: More *)
  40. (* Macintosh Toolbox very closely and test your component thoroughly. *)
  41. (* You'll definitely want some tools off of develop 15, including *)
  42. (* Komponent Killer, Reinstaller II and the "thing" dcmd. *)
  43.  
  44. (* This code is probably of adequate quality for most uses, but if *)
  45. (* you are using it to implement a commercial-quality system, you *)
  46. (* may want to rewrite it from the ground up. *)
  47.  
  48. (* Quinn "The Eskimo!" *)
  49.  
  50. (* with vast plagarism from... *)
  51.  
  52. (* Eric Kidd *)
  53. (* eric.kidd@dartmouth.edu *)
  54.  
  55. (* Thanks for all the work Eric! *)
  56.  
  57. interface
  58.  
  59.     uses
  60.         Components;
  61.  
  62.     function Main (var params: ComponentParameters; storage: Handle): ComponentResult;
  63.  
  64. implementation
  65.  
  66.     uses
  67. {$ifc undefined THINK_Pascal}
  68.         Types, Files, QuickDraw, Aliases, Packages, Memory, Errors, ToolUtils, Resources, 
  69.  
  70.         ICTypes, 
  71. {$endc}
  72.         Folders, ICCAPI, ICKeys, ICComponentSelectors, ICSpecificOverride;
  73.  
  74.     function ICGODecStr (l: longint): Str32;
  75.         var
  76.             tmpstr: Str255;
  77.     begin
  78.         NumToString(l, tmpstr);
  79.         ICGODecStr := tmpstr;
  80.     end; (* ICGODecStr *)
  81.  
  82. (*  ICGOFixCloneRefCon *)
  83.  
  84. (* See Inside Macintosh: More Macintosh Toolbox p. 6-35 for *)
  85. (* an overview of this silliness. It seems that when your globally- *)
  86. (* registered component is opened by an application, the system *)
  87. (* pulls a fast one under "certain circumstances" (not enough memory *)
  88. (* in the system heap) and "clones" a locally-registered version *)
  89. (* of your component, frying your RefCon in process. *)
  90.  
  91. (* What we need to do is determine if this is the case, and if so, *)
  92. (* recover the RefCon by locating the original copy of the component. *)
  93.  
  94. (* The Officially Sactioned Way to do this is a bit of a hack. Global *)
  95. (* components have an A5 world of zero when they are opened, but local *)
  96. (* ones have it pre-set to the parent application's value. If your *)
  97. (* supposedly global component detects that it has a pre-set A5 world, *)
  98. (* then it's been cloned. *)
  99.  
  100. (* To find the original copy of the component (which has the RefCon we *)
  101. (* need), we need to find another component that looks exactly like us, *)
  102. (* with the exception of a different component identifier. Unless we've *)
  103. (* been registered globally multiple times under the same name, this *)
  104. (* should work. FindNextComponent will do the job here. *)
  105.  
  106. (* The "practical upshot" of this: *)
  107. (* 1) Only call this routine when handling open messages *)
  108. (* 2) Call it before setting your instance's A5 world *)
  109. (* 3) Only call it if you should have been global *)
  110. (* 4) It won't work if you've been registered multiple times *)
  111. (*      under the same name. *)
  112. (* 5) Don't use the same manufacturer code for different *)
  113. (*      components with the same type/subtype *)
  114. (* 6) It may not work at all. I'm a college student, dammit, not a *)
  115. (*      programming guru. *)
  116.  
  117. (* Eric Kidd *)
  118. (* eric.kidd@dartmouth.edu *)
  119. (* 16 Dec 94 *)
  120.  
  121.     function ICGOFixCloneRefCon (self: ComponentInstance): ComponentResult;
  122.         var
  123.             err: OSErr;
  124.             junk: OSErr;
  125.             cd: ComponentDescription;
  126.             current: Component;
  127.     begin
  128.         err := noErr;
  129.         if (GetComponentRefcon(Component(self)) = 0) & (GetComponentInstanceA5(self) <> 0) then begin
  130.             (* if this component has not been opened & setup*)
  131.             (*     and we've been cloned*)
  132.  
  133.             (* get enough info about ourself to recognize the original *)
  134.             junk := GetComponentInfo(Component(self), cd, nil, nil, nil);
  135.             cd.componentFlagsMask := 0;        (* these shouldn't be relevant *)
  136.  
  137.             current := nil;
  138.             repeat
  139.                 (* loop until we find someone other than ourself *)
  140.                 current := FindNextComponent(current, cd);
  141.             until current <> Component(self);
  142.  
  143.             (* We didn't find any original--this happens often.*)
  144.             (* If we've been captured, we can't find the original*)
  145.             (*     copy. Best thing to do is return an error.*)
  146.  
  147.             if current = nil then begin
  148.                 err := paramErr;
  149.             end
  150.             else begin
  151.                 SetComponentRefcon(Component(self), GetComponentRefcon(current));
  152.             end; (* if *)
  153.         end; (* if *)
  154.         ICGOFixCloneRefCon := err;
  155.     end; (* ICGOFixCloneRefCon *)
  156.  
  157.     function ICGOGetSharedGlobals (globals: globalsHandle): ComponentResult;
  158.         (* If the shared have not yet been allocated, we'll try to set them*)
  159.         (* up and return them.*)
  160.         var
  161.             err: ComponentResult;
  162.             shared: sharedGlobalsPtr;
  163.             junk: OSErr;
  164.     begin
  165.         shared := sharedGlobalsPtr(GetComponentRefcon(Component(globals^^.self)));
  166.         globals^^.shared := shared;
  167.         if shared = nil then begin
  168.             shared := sharedGlobalsPtr(NewPtrSysClear(sizeof(sharedGlobals)));
  169.             err := MemError;
  170.             if err = noErr then begin
  171.                 globals^^.shared := shared;
  172.                 (* init our part of the shared globals *)
  173.                 shared^.delegate := nil;
  174.                 (* and remember the shared globals in our refcon *)
  175.                 SetComponentRefcon(Component(globals^^.self), longint(shared));
  176.  
  177.                 (* Since our shared globals get set up only once at registration*)
  178.                 (* time, here's the perfect place to move ourselves to the*)
  179.                 (* default position on the component list *)
  180.                 err := SetDefaultComponent(Component(globals^^.self), defaultComponentIdentical + defaultComponentAnyFlagsAnyManufacturer);
  181.             end; (* if *)
  182.             (* and init the specific globals *)
  183.             if err = noErr then begin
  184.                 junk := ICSOInitShared(globals);
  185.             end; (* if *)
  186.         end; (* if *)
  187.  
  188.         ICGOGetSharedGlobals := err;
  189.     end; (* ICGOGetSharedGlobals *)
  190.  
  191. (* Component Manager routines *)
  192.  
  193.     function ICGORegister (globals: globalsHandle): ComponentResult;
  194.         (* I'd love to allocate shared globals here, but certain *)
  195.         (*     versions of the Component Manager don't call ICGORegister. *)
  196.         (*     Additionally, calls to ICGOOpen and ICGOClose bracket *)
  197.         (*     the call if it does get made. Go figure. *)
  198.  
  199.         (* We actually return a Boolean value, false if we should be*)
  200.         (* registered and true if we shouldn't.*)
  201.     begin
  202.         ICGORegister := 0;
  203.     end; (* ICGORegister *)
  204.  
  205.     function ICGOUnregister (globals: globalsHandle): ComponentResult;
  206.         (* Eric's comment: *)
  207.         (*   Does this break if we've been cloned? Does the clone *)
  208.         (*       get unregistered seperately and double dispose? Hmm. *)
  209.         (* FIIK )-: *)
  210.         var
  211.             result: ComponentResult;
  212.             result2: ComponentResult;
  213.     begin
  214.         result := -1;
  215.         if globals^^.shared <> nil then begin
  216.             (* give the specifics opportunity to clean up its shared globals *)
  217.             result := ICSOCleanShared(globals);
  218.             (* clean up our part of the shared globals *)
  219.             result2 := UncaptureComponent(globals^^.shared^.delegate);
  220.             if result = noErr then begin
  221.                 result := result2;
  222.             end; (* if *)
  223.             (* dispose of the shared globals and set our refcon back to nil *)
  224.             DisposePtr(Ptr(globals^^.shared));
  225.             globals^^.shared := nil;
  226.             SetComponentRefcon(Component(globals^^.self), 0);
  227.         end; (* if *)
  228.         ICGOUnregister := result;
  229.     end; (* ICGOUnregister *)
  230.  
  231.     function ICGOCanDo (globals: globalsHandle; selector: integer): ComponentResult;
  232.     (* Handle the Component Manager CanDo request.*)
  233.         var
  234.             result: ComponentResult;
  235.     begin
  236.         case selector of
  237.             kComponentUnregisterSelect..kComponentOpenSelect: 
  238.                 result := 1;
  239.             otherwise begin
  240.                 result := ICSOCanDo(globals, selector);
  241.                 if result = delegateThisCallErr then begin
  242.                     result := ComponentFunctionImplemented(globals^^.delegate, selector);
  243.                 end
  244.                 else begin
  245.                     result := result + 1;
  246.                 end; (* if *)
  247.             end;
  248.         end; (* case *)
  249.         ICGOCanDo := result;
  250.     end; (* ICGOCanDo *)
  251.  
  252.     function ICGOFindDelegate (after: Component): Component;
  253.         var
  254.             cd: ComponentDescription;
  255.             found_cd: ComponentDescription;
  256.             current: Component;
  257.             found: boolean;
  258.     begin
  259.         cd.componentType := internetConfigurationComponentType;
  260.         cd.componentSubType := internetConfigurationComponentSubType;
  261.         cd.componentManufacturer := OSType(0);
  262.         cd.componentFlags := 0;
  263.         cd.componentFlagsMask := 0;
  264.         current := after;
  265.         found := false;
  266.         repeat
  267.             current := FindNextComponent(current, cd);
  268.             if current <> nil then begin
  269.                 if GetComponentInfo(current, found_cd, nil, nil, nil) = noErr then begin
  270.                     found := (found_cd.componentManufacturer <> kOurComponentManufacturer);
  271.                 end; (* if *)
  272.             end; (* if *)
  273.         until found or (current = nil);
  274.         if current = nil then begin
  275. (* DebugStr('ICGOFindDelegate failed to find one.'); *)
  276.         end; (* if *)
  277.         ICGOFindDelegate := current;
  278.     end; (* ICGOFindDelegate *)
  279.  
  280. (* ICGOOpen *)
  281.  
  282. (* This function has been substanially recrafted from the original. Cloning *)
  283. (* is now handled correctly (see the description of ICGOFixCloneRefCon) and error *)
  284. (* handling has been made more graceful by the addition of a dedicated control *)
  285. (* structure. A memory leak has been closed and OpenComponent can no longer *)
  286. (* be called on a NULL component instance. *)
  287.  
  288. (* If you're using the pascal version, you'll want to carefully examine the *)
  289. (* differences. *)
  290.  
  291.     function ICGOOpen (globals: globalsHandle; self: ComponentInstance): ComponentResult;
  292.         var
  293.             err: ComponentResult;
  294.             cap: Component;
  295.             toCapture: Component;
  296.     begin
  297.         globals := nil;
  298.         err := ICGOFixCloneRefCon(self);
  299.         if err = noErr then begin
  300.             globals := globalsHandle(NewHandleClear(sizeof(globalsRecord)));
  301.             err := MemError;
  302.         end; (* if *)
  303.         if err = noErr then begin
  304.             HLock(Handle(globals));
  305.  
  306.             globals^^.self := self;
  307.             SetComponentInstanceStorage(self, Handle(globals));
  308.             err := ICGOGetSharedGlobals(globals);
  309.         end; (* if *)
  310.  
  311.         if err = noErr then begin
  312.             (* If we haven't yet done so, find and capture the*)
  313.             (*     topmost IC component. We'll save the special*)
  314.             (*     component identifier which will permit us to*)
  315.             (* open it.*)
  316.             if globals^^.shared^.delegate = nil then begin
  317.                 toCapture := ICGOFindDelegate(Component(self));
  318.                 if toCapture = nil then begin
  319.                     err := icNothingToOverrideErr;
  320.                 end
  321.                 else begin
  322.                     globals^^.shared^.delegate := CaptureComponent(toCapture, Component(self));
  323.                 end; (* if *)
  324.             end; (* if *)
  325.             if err = noErr then begin
  326.                 globals^^.delegate := OpenComponent(globals^^.shared^.delegate);
  327.                 err := ComponentSetTarget(self, self);
  328.             end; (* if *)
  329.             if err = noErr then begin
  330.                 err := ICSOInitGlobals(globals);
  331.             end; (* if *)
  332.         end; (* if *)
  333.  
  334.         if globals <> nil then begin
  335.             HUnlock(Handle(globals));
  336.         end; (* if *)
  337.         if err <> noErr then begin
  338.             if globals <> nil then begin
  339.                 DisposeHandle(Handle(globals));
  340.                 SetComponentInstanceStorage(self, nil);
  341.             end; (* if *)
  342.         end; (* if *)
  343.  
  344.         ICGOOpen := err;
  345.     end; (* ICGOOpen *)
  346.  
  347.     function ICGOClose (globals: globalsHandle; self: ComponentInstance): ComponentResult;
  348.     (* Handle the Component Manager Close request. *)
  349.         var
  350.             err: ComponentResult;
  351.             junk: OSErr;
  352.     begin
  353.         err := noErr;
  354.         if globals <> nil then begin
  355.             junk := ICSOCleanGlobals(globals);
  356.             if globals^^.delegate <> nil then begin
  357.                 junk := CloseComponent(globals^^.delegate)
  358.             end; (* if *)
  359.             DisposeHandle(Handle(globals));
  360.         end; (* if *)
  361.         ICGOClose := err;
  362.     end; (* ICGOClose *)
  363.  
  364.     function ICGOTarget (globals: globalsHandle; new_target: ComponentInstance): ComponentResult;
  365.     (* Handle the Component Manager Target. *)
  366.         var
  367.             err: ComponentResult;
  368.     begin
  369.         globals^^.target := new_target;
  370.         if globals^^.delegate <> nil then begin
  371.             err := ComponentSetTarget(globals^^.delegate, new_target);
  372.         end
  373.         else begin
  374.             err := noErr;
  375.         end; (* if *)
  376.         ICGOTarget := err;
  377.     end; (* ICGOTarget *)
  378.  
  379. (* Internet Configuration specific routines *)
  380.  
  381.     function Main (var params: ComponentParameters; storage: Handle): ComponentResult;
  382.     (* Component entry point.  It's pretty neat IMHO. *)
  383.         var
  384.             proc: ProcPtr;
  385.             s: signedByte;
  386.             res: longint;
  387.     begin
  388.         proc := nil;
  389. {$ifc debug_component_entry_exit}
  390.         DebugStr(concat('Enter ', SelectorToStr(params.what)));
  391. {$endc}
  392.         case params.what of
  393.             (* Component Manager stuff *)
  394.             kComponentVersionSelect: 
  395.                 Main := internetConfigurationComponentInterfaceVersion;
  396.             kComponentCanDoSelect: 
  397.                 proc := @ICGOCanDo;
  398.             kComponentOpenSelect: 
  399.                 proc := @ICGOOpen;
  400.             kComponentCloseSelect: 
  401.                 proc := @ICGOClose;
  402.             kComponentTargetSelect: 
  403.                 proc := @ICGOTarget;
  404.             kComponentRegisterSelect: 
  405.                 proc := @ICGORegister;
  406.             kComponentUnregisterSelect: 
  407.                 proc := @ICGOUnregister;
  408.             (* this component type stuff *)
  409.             otherwise
  410.                 proc := ICSOWhatToOverride(globalsHandle(storage), params.what);
  411.         end; (* case *)
  412.         if storage <> nil then begin
  413.             s := HGetState(storage);
  414.             HLock(storage);
  415.         end; (* if *)
  416.         res := delegateThisCallErr;
  417.         if proc <> nil then begin
  418.             res := CallComponentFunctionWithStorage(storage, params, proc);
  419.         end; (* if *)
  420.         if res = delegateThisCallErr then begin
  421.             res := DelegateComponentCall(params, globalsHandle(storage)^^.delegate);
  422.         end; (* if *)
  423. {$ifc debug_component_entry_exit}
  424.         DebugStr(concat('Exit ', SelectorToStr(params.what), ' with result ', ICGODecStr(res)));
  425. {$endc}
  426.         Main := res;
  427.         if (storage <> nil) and (params.what <> kComponentCloseSelect) then begin
  428.             HSetState(storage, s);
  429.         end; (* if *)
  430.     end; (* Main *)
  431.  
  432. end. (* ICGenericOverride *)